package ch13;

import java.util.Date;
import java.util.ArrayList;

// ATM.java
// Represents an automated teller machine

public class ATM {
	private boolean customerAuthenticated; // whether user is authenticated
	private boolean adminAuthenticated; // whether admin is authenticated
	private int currentID; // current ID
	private Screen screen; // ATM's screen
	private Keypad keypad; // ATM's keypad
	private CashDispenser cashDispenser; // ATM's cash dispenser
	private DepositSlot depositSlot; // ATM's deposit slot
	private BankDatabase bankDatabase; // ATM information database

	// constants corresponding to customer main menu options
	private static final int BALANCE_INQUIRY = 1;
	private static final int WITHDRAWAL = 2;
	private static final int DEPOSIT = 3;
	private static final int EXIT_CUSTOMER = 4;

	// constants corresponding to admin main menu options
	private static final int VIEW_CUSTOMERS = 1;
	private static final int NEW_CUSTOMER = 2;
	private static final int DELETE_CUSTOMER = 3;
	private static final int EDIT_CUSTOMER = 4;
	private static final int ADD_OR_DELETE_ACCOUNT = 5;
	private static final int CALCULATE_MONTH = 6;
	private static final int EXIT_ADMIN = 7;

	// irrelevant stringarray for menu-visualization
	private ArrayList<String> stringArray = new ArrayList<String>();
	// initializes the date when the ATM starts
	Date date = new Date();

	// no-argument ATM constructor initializes instance variables
	public ATM() {
		customerAuthenticated = false; // user is not authenticated to start
		adminAuthenticated = false; // user is not authenticated to start
		currentID = 0; // no current account number to start
		screen = new Screen(); // create screen
		keypad = new Keypad(); // create keypad
		cashDispenser = new CashDispenser(); // create cash dispenser
		depositSlot = new DepositSlot(); // create deposit slot
		bankDatabase = new BankDatabase(); // create acct info database
	} // end no-argument ATM constructor

	// start ATM
	public void run() {
		// When run method starts, so does timerInterest. It is used to calculates interest.
		TimerInterest t1 = new TimerInterest(bankDatabase);
		t1.start();
		
		// welcome and authenticate user; 
		// loop while user is not yet authenticated
		while (!customerAuthenticated && !adminAuthenticated) {
			Logo(); // This method prints out the ATM logo
			screen.printHelper(" \n", 1);
			System.out.println("               " + date.toString());
			screen.printHelper(" \n", 1);
			
			stringArray.clear();
			stringArray.add("Welcome!");
			stringArray.add("Please Enter your account number");
			screen.setKasse(stringArray, 10);

			authenticateUser(); // authenticate user
			if (customerAuthenticated) 
			{
				// runs customerOptions() if customer is authenticated;
				customerOptions(); // customer is now authenticated
			}

			if (adminAuthenticated) 
			{
				// runs adminAuthenticated if admin is authenticated
				adminOptions(); // admin is now authenticated
			}

			customerAuthenticated = false; // reset before next ATM session
			adminAuthenticated = false; // reset before next ATM session
			currentID = 0; // reset before next ATM session
			stringArray.clear();
			stringArray.add("Thank you! Goodbye! ");
			screen.setKasse(stringArray, 10);
		} // end while

	} // end method run

	// attempts to authenticate user against database
	private void authenticateUser() {
		int userID = keypad.getInput(); // input userID
		stringArray.clear();
		stringArray.add("Enter your PIN");
		screen.setKasse(stringArray, 10); // prompt for PIN
		int pin = keypad.getInput(); // input PIN

		// set customerAuthenticated to boolean value returned by database
		customerAuthenticated = bankDatabase.authenticateCustomer(userID, pin);

		// set adminAuthenticated to boolean value returned by database
		adminAuthenticated = bankDatabase.authenticateAdmin(userID, pin);

		// check whether authentication succeeded for customer or admin
		if (customerAuthenticated || adminAuthenticated) {
			currentID = userID; // save userID
		} // end if
		else {
			stringArray.clear();
			stringArray.add("Invalid account number or PIN. Please try again.");
			screen.setKasse(stringArray, 10);
		} // end else
	} // end method authenticateUser
	
	// display the customer main menu and lets the customer choose which customer option he wants to perform
	private void customerOptions() {
		// local variable to store customer option currently being used
		Option currentCustomerOption = null;

		boolean userExited = false; // customer has not chosen to exit
		// loop while customer has not chosen the option to exit the system
		while (!userExited) {
			// show main menu and get user selection
			int customerMainMenuSelection = displayCustomerMainMenu();

			// decide how to proceed based on user's menu selection
			switch (customerMainMenuSelection) {
			// user chose to perform one of three customer options
			case BALANCE_INQUIRY:
			case WITHDRAWAL:
			case DEPOSIT:

				// initialize as new object of chosen type
				currentCustomerOption = createCustomerOption(customerMainMenuSelection);

				currentCustomerOption.execute(); // execute transaction
				break;
			case EXIT_CUSTOMER: // user chose to terminate session
				stringArray.clear();
				stringArray.add("Exiting the system... ");
				screen.setKasse(stringArray, 10);
				userExited = true; // this ATM session should end
				break;
			default: // user did not enter an integer from 1-4
				stringArray.clear();
				stringArray
						.add("\nYou did not enter a valid selection. Try again.");
				screen.setKasse(stringArray, 10);
				break;
			} // end switch
		} // end while
	} // end method customerOptions

	// display the admin main menu and lets the customer choose which admin option he wants to perform
	private void adminOptions() {
		// local variable to store admin option currently being used
		Option currentAdminOption = null;

		boolean userExited = false; // user has not chosen to exit

		// loop while user has not chosen option to exit system
		while (!userExited) {
			// show main menu and get user selection
			int adminMainMenuSelection = displayAdminMainMenu();

			// decide how to proceed based on user's menu selection
			switch (adminMainMenuSelection) {
			// user chooses to perform one of these 6 options
			case VIEW_CUSTOMERS:
			case NEW_CUSTOMER:
			case DELETE_CUSTOMER:
			case EDIT_CUSTOMER:
			case ADD_OR_DELETE_ACCOUNT:
			case CALCULATE_MONTH:
				// initialize as new object of chosen type
				currentAdminOption = createAdminOption(adminMainMenuSelection);

				currentAdminOption.execute(); // execute chosen adminOption
				break;
			case EXIT_ADMIN: // user chose to terminate session
				stringArray.clear();
				stringArray.add("Exiting the system... ");
				screen.setKasse(stringArray, 10);
				userExited = true; // this ATM session should end
				break;
			default: // user did not enter an integer from 1-9
				stringArray.clear();
				stringArray
						.add("\nYou did not enter a valid selection. Try again.");
				screen.setKasse(stringArray, 10);
				break;
			} // end switch
		} // end while
	} // end method adminOptions

	// display the customer main menu and return an input selection
	private int displayCustomerMainMenu() {
		stringArray.clear();
		stringArray.add("Main menu:");
		stringArray.add("1 - View my balance ");
		stringArray.add("2 - Withdraw cash ");
		stringArray.add("3 - Deposit funds ");
		stringArray.add("4 - Exit");
		stringArray.add("  ");
		stringArray.add("Enter a choice");
		screen.setKasse(stringArray, 10);
		
		return keypad.getInput(); // return user's selection
	} // end method displayCustomerMainMenu

	// display the admin main menu and return an input selection
	private int displayAdminMainMenu() {
		stringArray.clear();
		stringArray.add("Main menu:");
		stringArray.add("1 - View customers");
		stringArray.add("2 - New customers ");
		stringArray.add("3 - Delete customer ");
		stringArray.add("4 - Edit customer ");
		stringArray.add("5 - Add or delete accounts  ");
		stringArray.add("6 - Calculate interest");	
		stringArray.add("7 - Exit");
		stringArray.add("Enter a choice");
		screen.setKasse(stringArray, 10);

		return keypad.getInput(); // return admin's selection
	} // end method displayAdminMainMenu

	private Option createCustomerOption(int typeC) {
		Option tempC = null; // temporary Transaction variable

		// determine which type of Transaction to create
		switch (typeC) {
		case BALANCE_INQUIRY: // create new BalanceInquiry transaction
			tempC = new BalanceInquiry(currentID, screen, bankDatabase);
			break;
		case WITHDRAWAL: // create new Withdrawal transaction
			tempC = new Withdrawal(currentID, screen, bankDatabase, keypad,
					cashDispenser);
			break;
		case DEPOSIT: // create new Deposit transaction
			tempC = new Deposit(currentID, screen, bankDatabase, keypad,
					depositSlot);
			break;
		} // end switch

		return tempC; // return the newly created object
	} // end method createCustomerOption

	private Option createAdminOption(int typeA) {
		Option tempA = null;

		switch (typeA) {
		case VIEW_CUSTOMERS:
			tempA = new ViewCustomers(currentID, screen, bankDatabase, keypad);
			break;
		case NEW_CUSTOMER:
			tempA = new NewCustomer(currentID, screen, bankDatabase, keypad);
			break;
		case DELETE_CUSTOMER:
			tempA = new DeleteCustomer(currentID, screen, bankDatabase, keypad);
			break;
			case EDIT_CUSTOMER:
			tempA = new EditCustomer(currentID, screen, bankDatabase, keypad);
			break;
		case ADD_OR_DELETE_ACCOUNT:
			tempA = new AddOrDeleteAccount(currentID, screen, bankDatabase, keypad);
			break;
		case CALCULATE_MONTH:
			tempA = new CalculationMonth(currentID, screen, bankDatabase,
					keypad);
		} // end switch
		
		return tempA; // return the newly created object
	} // end method createAdminOption
	
		// This method prints out the ATM logo
		public void Logo() {
			// This prints out the ATM's startscreen (every time it starts)
			screen.printHelper(
					"              db   888888888888 88b           d88\n", 1);
			screen.printHelper(
					"             d88b       88      888b         d888\n", 1);
			screen.printHelper(
					"            d8'`8b      88      88`8b       d8'88\n", 1);
			screen.printHelper(
					"           d8'  `8b     88      88 `8b     d8' 88\n", 1);
			screen.printHelper(
					"          d8YaaaaY8b    88      88  `8b   d8'  88\n", 1);
			screen.printHelper(
					"         d8        8b   88      88   `8b d8'   88\n", 1);
			screen.printHelper(
					"        d8'        `8b  88      88    `888'    88\n", 1);
			screen.printHelper(
					"       d8'          `8b 88      88     `8'     88\n", 1);

			System.out
					.println("   ||====================================================================||");
			System.out
					.println("   ||//$\\\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\//$\\\\||");
			System.out
					.println("   ||(100)==================| FEDERAL RESERVE NOTE |================(100)||");
			System.out
					.println("   ||\\\\$//        ~         '------========--------'                \\\\$//||");
			System.out
					.println("   ||<< /        /$\\              // ____ \\\\                         \\ >>||");
			System.out
					.println("   ||>>|  12    //L\\\\            // ///..) \\\\         L38036133B   12 |<<||");
			System.out
					.println("   ||<<|        \\\\ //           || <||  >\\  ||                        |>>||");
			System.out
					.println("   ||>>|         \\$/            ||  $$ --/  ||        One Hundred     |<<||");
			System.out
					.println("||====================================================================||>||");
			System.out
					.println("||//$\\\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\//$\\\\||<||");
			System.out
					.println("||(100)==================| FEDERAL RESERVE NOTE |================(100)||>||");
			System.out
					.println("||\\\\$//        ~         '------========--------'                \\\\$//||\\||");
			System.out
					.println("||<< /        /$\\              // ____ \\\\                         \\ >>||)||");
			System.out
					.println("||>>|  12    //L\\\\            // ///..) \\\\         L38036133B   12 |<<||/||");
			System.out
					.println("||<<|        \\\\ //           || <||  >\\  ||                        |>>||=||");
			System.out
					.println("||>>|         \\$/            ||  $$ --/  ||        One Hundred     |<<||");
			System.out
					.println("||<<|      L38036133B        *\\\\  |\\_/  //* series                 |>>||");
			System.out
					.println("||>>|  12                     *\\\\/___\\_//*   1989                  |<<||");
			System.out
					.println("||<<\\      Treasurer     ______/Franklin\\________     Secretary 12 />>||");
			System.out
					.println("||//$\\                 ~|UNITED STATES OF AMERICA|~               /$\\\\||");
			System.out
					.println("||(100)===================  ONE HUNDRED DOLLARS =================(100)||");
			System.out
					.println("||\\\\$//\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\\\$//||");

		} //end Logo method
} // end class ATM